package br.edu.unifei.mestrado.mn;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.edu.unifei.mestrado.commons.graph.GraphWrapper;
import br.edu.unifei.mestrado.commons.partition.BestPartition;
import br.edu.unifei.mestrado.kl.BKL;
import br.edu.unifei.mestrado.kl.KL;
import br.edu.unifei.mestrado.kl.KLMemory;
import br.edu.unifei.mestrado.mem.graph.Graph;

public class MultinivelMemory extends TwoWayMultinivel {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	private GraphViewMem view = new GraphViewMem();

	protected Graph grafo;

	private String graphFileName;

	public MultinivelMemory(String graphFileName) {
		grafo = new Graph(GraphWrapper.NO_LEVEL, graphFileName);
		this.graphFileName = graphFileName;
	}

	@Override
	public void readGraph() {
		grafo.readGraph();
	}

	@Override
	protected GraphWrapper createNewGraph(Integer level) {
		Graph grafo = new Graph(level, graphFileName);
		return grafo;
	}

	protected BKL getBKLObject(final GraphWrapper newGrafo) {

		// TODO: retirar o new grafro de dentro do construtor, pq aqui o grafo já existe
		BKLMemory bkl = new BKLMemory(graphFileName) {
			@Override
			public void readGraph() {
				this.grafo = newGrafo;
			}
		};
		bkl.readGraph();// UTIL: tem que chamar o readGraph para salvar o newGrafo no objeto acima
		return bkl;
	}

	@Override
	protected GraphWrapper getGrafo() {
		return grafo;
	}

	protected KL getKLObject(final GraphWrapper newGrafo) {
		// TODO: retirar o new grafo de dentro do construtor, pq aqui o grafo já existe
		// TODO: verificar se precisa realmente do KLMemory aqui.
		KLMemory kl = new KLMemory(graphFileName) {
			@Override
			public void readGraph() {
				this.grafo = newGrafo;
			}
		};
		kl.readGraph(); // UTIL: tem que chamar o readGraph para salvar o newGrafo no objeto acima
		return kl;
	}

	/**
	 * 1) Executa o particionamento 2-way usando o KL.
	 */
	protected BestPartition executePartition(GraphWrapper grafo) {
		long delta = System.currentTimeMillis();
		KL kl = getKLObject(grafo);

		BestPartition result = kl.executeKL();
		result.printSets();
		delta = System.currentTimeMillis() - delta;
		logger.warn("Tempo gasto no KL: " + delta + " ms");
		return result;
	}

	@Override
	protected BestPartition refineGraph(GraphWrapper graph, int level) {
		BKL bkl = getBKLObject(graph);
		
		//UTIL: o BKL usa o generateBoundaryPartition para obter as arestas do corte inicial
		BestPartition part = bkl.executeBKL(level);
		return part;
	}

	@Override
	public void initView(GraphWrapper initialGraph) {
		view.initView(initialGraph);
	}

	@Override
	public void setShowView(boolean showView) {
		view.setShowView(showView);
	}

	@Override
	public void updateView(GraphWrapper grafo, int level, String it, int cutWeight) {
		view.updateView(grafo, level, it, cutWeight);
	}

	@Override
	public void updateViewCoarsed(GraphWrapper grafo, int level, String it, int cutWeight) {
		view.updateViewCoarsed(grafo, level, it, cutWeight);
	}
	
	@Override
	public void repaint() {
		view.repaint();
	}
}
